﻿using System.Collections.Generic;
using System.Diagnostics;

using Game.Actions;
using Game.Common;
using Game.Level;
using Game.Map;
using Game.Map.Extensions;
using Game.Objects;
using Game.PathFinder;
using Game.StateMachine;

namespace Game.Ai.Internal.States.Patrol
{
    class StateIdPatrol : StateId
    {
        public StateIdPatrol() : base("PatrolState") {}
    }
    
    class PatrolState : State
    {
        readonly ActionExecutor _actionExecutor;
        
        public PatrolState(ActionExecutor actionExecutor)
            : base(new StateIdPatrol())
        {
            _actionExecutor = actionExecutor;
        }
        
        public override StateId CheckTransitions(object contoller)
        {
            var ai = contoller as AiController;
            Debug.Assert(ai != null, "ai != null");
            
            var field = AiUtil.FindOther(ai);
            if (field != null)
            {
                var vehicleField = ai.GameMapView.FindItem(field.VehicleX().Vehicle);

                if (vehicleField != null)
                {
                    var attackingField = ai.GameMapView.FindItem(ai.Vehicle);
                    var path = GamePath.CreateDirectPath(
                        attackingField.Point, vehicleField.Point);

                    if (path.Distance <= 1)
                    {
                        return new StateIdAttack();
                    }

                    return new StateIdPersue();
                }
            }

            return new StateIdPatrol();
        }

        class FieldComparer : IComparer<IMapFieldView>
        {
            readonly Vehicle _vehicle;

            public FieldComparer(Vehicle vehicle)
            {
                _vehicle = vehicle;
            }

            public int Compare(IMapFieldView x, IMapFieldView y)
            {
                var left = x.TerrianX().TerrainCost;
                var right = y.TerrianX().TerrainCost;
                var leftX = x.Extensions.Find<BreadcumbExtension>();
                var rightX = y.Extensions.Find<BreadcumbExtension>();

                if (leftX.Dictionary.ContainsKey(_vehicle))
                {
                    int count = leftX.Dictionary[_vehicle];
                    left += count * 0.25;
                }

                if (rightX.Dictionary.ContainsKey(_vehicle))
                {
                    int count = rightX.Dictionary[_vehicle];
                    right += count * 0.25;
                }

                return left.CompareTo(right);
            }
        }

        public override void DoTurn(
            IGameMapView view, 
            GameLevels levels,
            object contoller, 
            GameTurn turn)
        {
            for(;;)
            {
                var ai = contoller as AiController;
                Debug.Assert(ai != null, "ai != null");

                if (ai.Vehicle.Movement.Value <= 0)
                {
                    break;
                }

                var start = ai.GameMapView.FindItem(ai.Vehicle);
                if (start == null || start.VehicleX().Vehicle == null)
                {
                    break;
                }

                var list = new List<IMapFieldView>();
                foreach (var field in MapUtil.GetAdjacentViewFields(ai.GameMapView, start.Point))
                {
                    if (field.Point == start.Point)
                    {
                        continue;
                    }

                    if (field.VehicleX().Vehicle != null)
                    {
                        continue;
                    }

                    var ext = field.Extensions.Find<BreadcumbExtension>();
                    if (ext == null)
                    {
                        ext = new BreadcumbExtension();
                        field.Extensions.Add(ext);
                    }

                    list.Add(field);
                }

                GamePath path = null;
                for (;;)
                {
                    list.Sort(new FieldComparer(ai.Vehicle));
                    if (list.Count == 0)
                    {
                        break;
                    }

                    var target = list[0];
                    list.Remove(target);

                    var finder = FinderFactory.Create(ai.GameMapView, start, target);
                    path = finder.Find();
                    if (path == null)
                    {
                        continue;
                    }

                    if (path.CalcTerrainCost(ai.GameMap) > ai.Vehicle.Movement.Value)
                    {
                        continue;
                    }

                    break;
                }

                if (path == null)
                {
                    break;
                }

                var next = path.Points[1];
                if (!ai.GameMapView.Fields.Contains(next))
                {
                    break;
                }
                
                var end = ai.GameMapView.Fields[next];
                var pair = new GamePath(start.Point, end.Point);

                bool same = (start.Point.X == end.Point.X &&
                             start.Point.Y == end.Point.Y);
                GameDebug.Assert(!same);

                var breadcrumb = end.Extensions.Find<BreadcumbExtension>();
                if (!breadcrumb.Dictionary.ContainsKey(ai.Vehicle))
                {
                    breadcrumb.Dictionary.Add(ai.Vehicle, 1);
                }
                else
                {
                    int count = breadcrumb.Dictionary[ai.Vehicle];
                    breadcrumb.Dictionary[ai.Vehicle] = ++count;
                }

                var move = new MoveUnit(ai.GameMapView, ai.Vehicle, pair);
                if (move.CanExecute())
                {
                    _actionExecutor.ExecuteLater(ai.GameMapView, levels, turn, move);
                }
                
                break;
            }
        }

    }
}


